﻿namespace NetFx.SMIL.Definitions
{
  using System;
  using System.Text;
  using System.Collections;
  using System.Collections.Generic;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using System.Security;
  using System.Security.Permissions;

  using NetFx.MSIL;
  using NetFx.SMIL.References;

  public class VariableDef : ReflectDef
  {
    #region Statics
    /// <summary>
    /// 缺省的变量名称。
    /// </summary>
    public static string DefaultVariableName = "var";
    public static VariableDef of(string name)
    {
      return new VariableDef(name);
    }
    public static VariableDef of(LocalVariableInfo variable)
    {
      return new VariableDef(variable);
    }
    public static VariableDef of(string name, LocalVariableInfo variable)
    {
      return new VariableDef(name, variable);
    }
    #endregion
    #region Fields
    protected TypeRef variableType = null;
    protected int index = 0;
    protected bool isPinned = false;
    #endregion
    #region Properties
    public override DefType DefinitionType
    {
      get { return DefType.Variable; }
    }
    public virtual TypeRef VariableType
    {
      get
      {
        return this.variableType;
      }
      set
      {
        this.variableType = value;
      }
    }
    public virtual int Index
    {
      get
      {
        return this.index;
      }
      set
      {
        this.index = value;
      }
    }
    public virtual bool IsPinned
    {
      get
      {
        return this.isPinned;
      }
      set
      {
        this.isPinned = value;
      }
    }
    #endregion
    #region Constructors
    public VariableDef(string name):base(name)
    {

    }
    public VariableDef(string name, Type variableType)
      : this(name)
    {
      this.variableType =TypeRef.of(variableType);
    }
    public VariableDef(string name, Type variableType, int index)
      : this(name, variableType)
    {
      this.index = index;
    }
    public VariableDef(LocalVariableInfo variable):this(String.Empty,variable)
    {

    }
    public VariableDef(string name, LocalVariableInfo variable):this(name)
    {
      this.OnReflecting(variable);
    }
    #endregion
    #region Methods
    #region Internals
    protected override AnyGenerator OnCompleting(AnyGenerator generator)
    {
      if (generator is VariableGenerator)
      {
        ((VariableGenerator)generator).Name = this.name;
        ((VariableGenerator)generator).Index = this.index;
        ((VariableGenerator)generator).VariableType = this.VariableType.ReflectInfo;
        ((VariableGenerator)generator).IsPinned = this.isPinned;
      }
      return base.OnCompleting(generator);
    }
    protected override AnyGenerator OnDefining(AnyGenerator container)
    {
      if (container is MethodGenerator)
      {
        return ((MethodGenerator)container).DefineVariable(this.name, this.VariableType.ReflectInfo, this.index, this.isPinned);
      }
      return base.OnDefining(container);
    }
    protected override ReflectDef OnReflecting(object source)
    {
      if (source is LocalVariableInfo)
      {
        LocalVariableInfo variable = source as LocalVariableInfo;
        this.index = variable.LocalIndex;
        this.isPinned = variable.IsPinned;
        this.variableType = TypeRef.of(variable.LocalType);

        this.name = this.OnNamingVariable(this.index, this.variableType);
      }
      return base.OnReflecting(source);
    }
    protected override void OnBreakingReference()
    {
      this.Break(this.VariableType);
      base.OnBreakingReference();
    }
    protected virtual string OnNamingVariable(int index, TypeRef type)
    {
      return type != null ? this.OnNamingInstance(type.Name) + index : DefaultVariableName + index;
    }
    #endregion
    #endregion
  }
}